// UECGIAction.cpp
#include <winsock2.h>
#include <io.h>
#include <tchar.h>
#include <stdio.h>
#include <time.h>

// UELogger Support
#include "litelog.h"
extern "C" int logfd = 0;

#include "libue.h"
#include "uecgi.h"

int main(int argc, char** argv)
{
	int ret = 0;
	int s = 0;
	ue_update_data *update_data = NULL;
	time_t systime = 0;

	printf("\r\n");

	/* get current time stamp */
	time(&systime);

	/* initialize debug log */
	logfd = InitCGILogFile(NULL);
#if defined(_DEBUG) || defined(DEBUG)
	loglevel = DEBUG_LOG_LEVEL_INFO;
#endif

	/* initialize windows socket */
	dbglog("Initialize windows socket", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);
	if (!InitWinSock2())
	{
		dbglog("Initialize windows socket failed.", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__);
		printf("{\"status\": -2, \"description\": \"System Error - Initialize windows socket failed!\"}");

		if (logfd > 0)
			_close(logfd);

		return -2;
	}

	CUECGIHttp uecgihttp;
	CUECGIDatabase uecgidb;

	/* get sessionid */
	const char* session_id = uecgihttp.GetSessionID();
	if (!session_id || strlen(session_id) == 0)
	{
		dbglog("SessionID is empty.", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__);
		printf("{\"status\": 8, \"description\": \"Authentication Error - Login Firstly!\"}");
		ret = 8;
		goto Exit;
	}
	dbglogex("Get session_id success: %s", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, session_id);

	/* get http request body (the CSRF token and ueid) */
	int len = uecgihttp.GetBodyLength();
	if (len == 0)
	{
		dbglogex("Invalid Conetent Length: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, len);
		printf("{\"status\": 2, \"description\": \"Invalid Request - Content Length Invalid!\"}");
		ret = -2;
		goto Exit;
	}
	dbglogex("HTTP request body length: %d", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, len);

	if (!uecgihttp.ParseQueries((char*)uecgihttp.GetBody()))
	{
		dbglog("Parse http queries failed.", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__);
		printf("{\"status\": 10, \"description\": \"UE Error - Parse HTTP Queries Failed!\"}");
		ret = 10;
		goto Exit;
	}
	dbglog("Parse http queries success.", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

	/* connect to database and read the relation ship between session_id, CSRF token and password */
	if (!uecgidb.Connect())
	{
		dbglog("Connect to CGI database failed.", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__);
		printf("{\"status\": 6, \"description\": \"UE Error - Connect to database failed!\"}");
		ret = 6;
		goto Exit;
	} /* connect to database failed */
	dbglog("Connect to database success", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

	char password[MAX_BUF_LEN];
	int token = atoi(uecgihttp.GetQuery(PARAMETER_TOKEN_NAME));
	if (!uecgidb.GetAuthentication(session_id, token, password, MAX_BUF_LEN))
	{
		dbglog("Can't find related session info", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__);
		printf("{\"status\": 11, \"description\": \"Authentication Error - Session Timeout!\"}");
		ret = 11;
		goto Exit;
	} /* get password failed */
	dbglogex("Get password success: %s", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__, password);

	/* connect to UE server and authenticate the password */
	int err = ue_connect(GetUEServerAddress(), GetUEServerPort(), &s);
	if (err)
	{
		dbglogex("Connect to UE server failed with return value: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, err);
		printf("{\"status\": 4, \"description\": \"UE Error - Connect to back-end server failed!\"}");
		ret = 4;
		goto Exit;
	}
	dbglog("Connect to UE server success", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

	err = ue_authenticate(s, password);
	if (err)
	{
		dbglogex("Authenticate failed with return value: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, err);
		printf("{\"status\": 5, \"description\": \"UE Error - Authenticate failed!\"}");
		ret = 5;
		goto Exit;
	}
	dbglog("Authenticate success", DEBUG_LOG_LEVEL_INFO, logfd, __FILE__, __LINE__);

	/* send action request */
	ue_action_data action_data;
	action_data.type = atoi(uecgihttp.GetQuery(PARAMETER_ACTION_NAME));
	action_data.ueid = atoi(uecgihttp.GetQuery(PARAMETER_UEID_NAME));
	action_data.x = atoi(uecgihttp.GetQuery(PARAMETER_TARGET_X_NAME));
	action_data.y = atoi(uecgihttp.GetQuery(PARAMETER_TARGET_Y_NAME));
	err = ue_action(s, &action_data, &update_data);
	if (err)
	{
		dbglogex("Action failed with return value: %d", DEBUG_LOG_LEVEL_ERRO, logfd, __FILE__, __LINE__, err);
		printf("{\"status\": 13, \"description\": \"UE Error - action failed!\"}");
		ret = 13;
		goto Exit;
	}

	/* respond client */
	printf("{\"status\": 0, \"description\": \"Action success!\", \"ueid\": %d, \"width\": %d, \"height\": %d, \"count\": %d", update_data->ueid, update_data->width, update_data->height, update_data->count);
	if (update_data->count > 0)
	{
		printf(", \"item\": [");
		for (int i = 0; i < update_data->count; i++)
		{
			if ( i != 0)
				printf(", ");
			printf("{\"left\": %d, \"top\": %d, \"width\": %d, \"height\": %d, \"data\": \"%s\"}", update_data->items[i].left, update_data->items[i].top, update_data->items[i].width, update_data->items[i].height, update_data->items[i].data);
		}
		printf("]");
	}
	printf("}");

Exit:
	uecgidb.Close();

	ue_response_free(NULL, update_data);

	if (s > 0)
		closesocket(s);

	WSACleanup();

	if (logfd > 0)
	{
		_close(logfd);
		logfd = 0;
	}

	return ret;
}